
#include "Window.h"
#include "graphics/GLState.h"
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
using namespace Umikaze::Core;

std::unique_ptr<Window> Window::_instance;
bool Window::keys[1024];
bool Window::keysPressed[1024];

void Window::framebuffer_size_callback(GLFWwindow *window, int width,
                                       int height) {
  _instance->changePixelSize(width, height);
}

void Window::mouse_callback(GLFWwindow *window, double xpos, double ypos) {
  static bool firstMouse = true;
  static float lastX = 0, lastY = 0;
  ;
  if (firstMouse) {
    lastX = xpos;
    lastY = ypos;
    firstMouse = false;
  }

  GLfloat xoffset = xpos - lastX;
  GLfloat yoffset = lastY - ypos;

  lastX = xpos;
  lastY = ypos;

  gDefaultCamera->ProcessMouseMovement(xoffset, yoffset);
};

void Window::scroll_callback(GLFWwindow *window, double xoffset,
                             double yoffset) {
  gDefaultCamera->ProcessMouseScroll(yoffset);
}

void Window::keyborad_callback(GLFWwindow *window, int key, int scancode,
                               int action, int mode) {
  if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
    glfwSetWindowShouldClose(window, GL_TRUE);

  if (key >= 0 && key <= 1024) {
    if (action == GLFW_PRESS)
      keys[key] = true;
    else if (action == GLFW_RELEASE) {
      keys[key] = false;
      keysPressed[key] = false;
    }
  }
}

void Window::DoCameraMove(float deltaTime) {
  if (keys[GLFW_KEY_W])
    gDefaultCamera->ProcessKeyboard(FORWARD, deltaTime);
  if (keys[GLFW_KEY_S])
    gDefaultCamera->ProcessKeyboard(BACKWARD, deltaTime);
  if (keys[GLFW_KEY_A])
    gDefaultCamera->ProcessKeyboard(LEFT, deltaTime);
  if (keys[GLFW_KEY_D])
    gDefaultCamera->ProcessKeyboard(RIGHT, deltaTime);
  if (keys[GLFW_KEY_Q])
    gDefaultCamera->ProcessKeyboard(UP, deltaTime);
  if (keys[GLFW_KEY_E])
    gDefaultCamera->ProcessKeyboard(DOWN, deltaTime);

  // if (keys[GLFW_KEY_SPACE] && !keysPressed[GLFW_KEY_SPACE])
  // {
  //     shadows = !shadows;
  //     keysPressed[GLFW_KEY_SPACE] = true;
  // }
}

bool Window::init(int width, int height) {
  glfwInit();
  glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
  glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
  glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif

  // glfw window creation
  // --------------------
  _window = glfwCreateWindow(width, height, "LearnOpenGL", NULL, NULL);
  if (_window == NULL) {
    std::cerr << "Failed to create GLFW window" << std::endl;
    glfwTerminate();
    return false;
  }
  glfwMakeContextCurrent(_window);
  glfwSetFramebufferSizeCallback(_window, framebuffer_size_callback);
  glfwSetCursorPosCallback(_window, mouse_callback);
  glfwSetScrollCallback(_window, scroll_callback);
  glfwSetKeyCallback(_window, keyborad_callback);

  // tell GLFW to capture our mouse
  // glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);

  // glad: load all OpenGL function pointers
  // ---------------------------------------
  if (glewInit() != GLEW_OK) {
    std::cerr << "glew初始化失败" << std::endl;
    glfwTerminate();
    return false;
  }

  _width = width;
  _height = height;

  glfwGetFramebufferSize(_window, &width, &height);

  changePixelSize(width, height);

  return true;
}

bool Window::shouldClose() { return glfwWindowShouldClose(_window); }

void Window::startDraw() {
  float currentFrame = glfwGetTime();
  _deltaTime = currentFrame - _lastFrame;
  _lastFrame = currentFrame;
  DoCameraMove(_deltaTime);
}

void Window::endDraw() {
  auto &state = GlState::instance();
  state->bindFramebuffer(0);
  glfwSwapBuffers(_window);
  glfwPollEvents();
}

void Window::setWindowSize(int width, int height) {
  _width = width;
  _height = height;
  glfwSetWindowSize(_window, width, height);
}

Window::~Window() { glfwTerminate(); }